package mspbots.qbd.online.core.creditmemo;

import com.fasterxml.jackson.databind.JsonNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import mspbots.qbd.common.QueryParams;
import mspbots.qbd.common.RabbitKeys;
import mspbots.qbd.common.ResultMsg;
import mspbots.qbd.common.ResultSync;
import mspbots.qbd.online.core.AbstractToolsUtil;
import mspbots.qbd.online.core.BaseSyncService;
import mspbots.qbd.online.oauth.TokenState;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.time.LocalDateTime;
import java.util.UUID;

@Log4j2
@Service
@RequiredArgsConstructor
public class CreditMemoServiceImpl extends AbstractToolsUtil implements BaseSyncService {
    private Flux<JsonNode> query() {
        QueryParams queryCreditMemo = QueryParams.withDefault("select * from CreditMemo ");
        return this.get(QueryParams.withCount("select count(*) from CreditMemo "))
                .map(jsonNode -> jsonNode.get("totalCount").intValue())
                .filter(count -> count > 0)
                .flatMapMany(count -> this.autoPaging(count, queryCreditMemo));
    }

    private Flux<JsonNode> autoPaging(long count, QueryParams queryCreditMemo) {
        return this.get(queryCreditMemo)
                .expand(jsonNode -> {
                    JsonNode startPositionNode = jsonNode.get("startPosition");
                    if (ObjectUtils.isEmpty(startPositionNode)) {
                        return Mono.empty();
                    }
                    int start = startPositionNode.intValue() + queryCreditMemo.getPageSize();
                    if (start > count) {
                        return Mono.empty();
                    }
                    queryCreditMemo.setPage(queryCreditMemo.getPage() + 1);
                    return this.get(queryCreditMemo);
                }).flatMap(jsonNode -> Flux.fromIterable(jsonNode.withArray("CreditMemo")));
    }

    private Mono<JsonNode> get(QueryParams queryCreditMemo) {
        return this.onlineClient.fetch("/company/{realmId}/query", queryCreditMemo);
    }

    @Override
    public Mono<Void> syncData(TokenState tokenState) {
        ResultSync resultSync = ResultSync.withDefault("CREDIT-MEMO-SYNC");
        return this.query()
                .subscriberContext(ctx -> ctx.put("tokenState", tokenState))
                .subscriberContext(ctx -> ctx.put("resultSync", resultSync))
                .doOnNext(result -> this.syncResult(tokenState.getTenantId(), resultSync.getRequestId(), result))
                .then();
    }

    private void syncResult(Long tenantId, UUID id, JsonNode resultNode) {
        Long entityId = Long.parseLong(resultNode.get("Id").textValue());
        this.sendEntity(RabbitKeys.CREDIT_MEMO_ONLINE_SYNC_QUEUE_KEY, ResultMsg.builder()
                .requestId(id).id(entityId)
                .action("none").entity(resultNode).tenantId(tenantId)
                .syncDate(LocalDateTime.now()).build());
    }
}
